<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>函数</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="css/default.css" rel="stylesheet" type="text/css">
</head>

<body>
<h1>函数</h1>

<h2>目录</h2>
<ul>
  <li><a href="#intro">入门和简单示例</a></li>
  <li><a href="#param">参数</a></li>
  <li><a href="#optional">可选参数</a></li>
  <li><a href="#Variadic">可变参数函数</a></li>
  <li><a href="#Locals">局部变量</a></li>
  <li><a href="#DynCall">动态调用函数 </a></li>
  <li><a href="#ShortCircuit">优化布尔求值</a></li>
  <li><a href="#gosub">在函数中使用子程序</a></li>
  <li><a href="#remarks">Return, Exit, 和一般说明</a></li>
  <li><a href="#include">使用 #Include 在多个脚本间共享函数</a></li>
  <li><a href="#lib">函数库: 标准库和用户库</a></li>
  <li><a href="#BuiltIn">内置函数</a></li>
</ul>
<h2><a name="intro" id="intro"></a>入门和简单示例</h2>
<p><a name="define"></a>函数类似于子程序 (<a href="commands/Gosub.htm">Gosub</a>), 不过它可以从其调用者那里接受参数 (输入). 此外, 它还可以返回值给其调用者. 思考后面这个接受两个数字并返回它们的和的简单函数:</p>
<pre>Add(x, y)
{
    return x + y   <em>; "<a href="commands/Return.htm">Return</a>" 要求一个 <a href="Variables.htm#Expressions">表达式</a>.</em>
}</pre>
<p>上面的被成为函数 <em>定义</em> 因为它创建了一个名称为 "Add" (不区分大小写) 的函数并且确立了调用它时必须确切地提供两个参数 (x 和 y). 要调用此函数, 把它的结果通过 <strong><a href="commands/SetExpression.htm">:=</a></strong><a href="commands/SetExpression.htm"> 运算符</a> 赋值给一个变量. 例如:</p>
<pre>Var := Add(2, 3)  <em>; 数字 5 将被保存到 Var 中.</em></pre>
<p>并且, 调用函数时可以不保存其返回值:</p>
<pre>Add(2, 3)</pre>
<p> 但在这样的情况中, 任何函数返回的值会被丢弃; 所以除非函数产生了返回值外的其他效果, 否则这个调用没有意义.</p>
<p>因为函数调用是一个 <a href="Variables.htm#Expressions">表达式</a>, 任何在其参数列表中的变量名称都不应该包围在百分号中. 与之相比, 原义的字符串应该包围在双引号中. 例如:</p>
<pre>if <a href="#InStr">InStr</a>(MyVar, "fox")
    MsgBox The variable MyVar contains the word fox.</pre>
<p>最后, 可以在任何命令的参数中调用函数 (除了像 <a href="commands/StringLen.htm">StringLen</a> 命令中的那些 OutputVar 和 InputVar 参数). 然而, 不支持 <a href="Variables.htm#Expressions">表达式</a> 的参数必须使用 "% " 前缀, 例如:</p>
<pre>MsgBox <strong>%</strong> "The answer is: " <strong>.</strong> Add(3, 2)</pre>
<p>在原生支持表达式的参数中也允许使用 "% " 前缀, 但它会被简单的忽略.</p>
<h2><a name="param" id="param"></a>参数</h2>
<p>一个函数被定义时, 其参数都列出在其名称后面的括号中 (在其名称和开括号之间不能含有空格). 如果函数不接受任何参数, 把括号留空; 例如: GetCurrentTimestamp().</p>
<p><a name="ByRef"></a><strong>ByRef 参数</strong>: 从函数角度看, 参数的实质是 <a href="#Locals">局部变量</a> 除非它们被定义为 <em>ByRef</em> 类型, 例如:</p>
<pre>Swap(ByRef Left, ByRef Right)
{
    temp := Left
    Left := Right
    Right := temp
}</pre>
<p>在上述例子中, <em>ByRef</em> 的使用让每个参数变成从调用者传递进来的变量的一个别名. 换句话说, 参数和调用者的变量都引用内存中相同的内容. 这样允许 Swap 函数通过移动 <em>Left</em> 的内容到 <em>Right</em> 中来修改调用者的变量, 反之亦然.</p>
<p>与之相比, 在上述例子中如果没有使用 <em>ByRef</em>, <em>Left</em> 和 <em>Right</em> 将是调用者变量的副本, 因此 Swap 不会产生外部影响.</p>
<p>由于 <a href="commands/Return.htm">return</a> 只能送回一个值给函数调用者, 所以可以使用 <em>ByRef</em> 送回更多的结果. 这是由函数向调用者传递进来的变量 (通常为空) 储存一个值来实现的.</p>
<p>当传递大量字符串到函数时, <em>ByRef</em> 提高了性能并且通过避免生成字符串的副本节约了内存. 同样地, 使用 <em>ByRef</em> 送回一个长字符串给调用者通常比一些方式例如 <code>Return HugeString 执行的更好</code>.</p>
<p><span class="ver">[AHK_L 60+]:</span> 如果不是可修改的变量被传递给 ByRef 参数, 函数表现的就像关键字 "ByRef" 没有那样. 例如, <code>Swap(A_Index, i)</code> 保存 <i>A_Index</i> 的值到 <i>i</i>, 但是一旦 <i>Swap</i> 返回后赋值给 <i>Left</i> 的值被丢弃了.</p>
<p>已知限制:</p>
<ul>
  <li>不能向函数的 <em>ByRef</em> 参数传递 <a href="misc/Clipboard.htm">Clipboard</a>, <a href="Variables.htm#BuiltIn">内置变量</a> 或 <a href="Variables.htm#env">环境变量</a>, 即使脚本中没有 <a href="commands/_NoEnv.htm">#NoEnv</a> 时.</li>
  <li><a name="recurse"></a>尽管一个函数可以递归调用它自身, 如果它传递它自己的一个 <a href="#Locals">局部变量</a> 或非 ByRef 参数给自身的 <em>ByRef</em>, 新一层的 <em>ByRef </em>参数将引用它自身那个名称的局部变量而不是之前层的. 然而, 当函数传递给它自身一个 <a href="#Global">全局变量</a>, <a href="#static">静态变量</a> 或 <em>ByRef</em> 参数时不会产生这样的问题.</li>
  <li>如果一个参数在函数调用中被解析为一个变量(例如 <code>Var</code> 或 <code>++Var</code> 或 <code>Var*=2</code>), 它左边或右边的其他参数可以在它被传递给函数前修改这个变量. 例如, <code>func(Var, Var++)</code> 会意外地传递 1 和 0 当 <em>Var</em> 初始为 0 时, 即使函数的首个参数不是 <em>ByRef</em> 类型. 因为这种行为是违反常规的, 可能在将来的版本中改变.</li>
</ul>
<h2 id="optional">可选参数</h2>
<p>定义一个函数时, 可以把它的一个或多个参数标记为可选的. 这可以通过在参数后添加一个等号后面跟着默认值实现. 后面的函数中其 Z 参数被标记为可选的:</p>
<pre>Add(X, Y, Z=0) {
    return X + Y + Z
}</pre>
<p>当调用者传递 <strong>三个</strong> 参数给上面的函数时, 参数 Z 的默认值被忽略. 但当调用者仅传递 <strong>两个</strong> 参数时, Z 自动获取默认值 0.</p>
<p>可选参数不能被孤立地放在参数列表的中间. 换句话说, 在首个可选参数右边的所有参数都必须标记为可选的. <span class="ver">[AHK_L 31+]:</span> 调用函数时参数列表中间的可选参数可以省略, 除非是函数调用是动态的:</p>
<pre>Func(1,, 3)
Func(X, Y=2, Z=0) {  <em>; 注意此时 Z 必须是可选的.</em>
    MsgBox %X%, %Y%, %Z%
}</pre>
<p><a name="OptionalByRef"></a>在 1.0.46.13+ 版本中, <a href="#ByRef">ByRef 参数</a> 也支持默认值; 例如: <code>Func(ByRef p1 = "")</code>. 每当调用者省略这样的参数时, 函数会创建一个包含默认值的局部变量; 换句话说, 函数表现的就像关键字 "ByRef" 没有那样.</p>
<p>参数的默认值必须是下列形式的其中一种: 真, 假, 原义的整数, 原义的浮点数或引号包围的/原义的字符串如 "fox" 或 "" (但在 1.0.46.13+         之前的版本中字符串只支持 "").</p>
<h2 id="Variadic">可变参数函数 <span class="ver">[AHK_L 60+]</span></h2>
<p>定义一个函数时, 在最后一个参数后面写一个星号来标记此函数为可变参数的, 允许它接收可变数目的参数:</p>
<pre>Join(sep, <b class="blue">params*</b>) {
    for index,param in params
        str .= param . sep
    return SubStr(str, 1, -StrLen(sep))
}
MsgBox % Join("`n", "one", "two", "three")</pre>
<p>调用可变参数函数时, 通过保存在函数的最后参数中的对象可以访问剩余的参数. 函数的首个剩余参数在 <code><i>params</i>[1]</code>, 第二个在 <code><i>params</i>[2]</code> 等等. 和所有标准对象一样, 使用 <code><i>params</i>.MaxIndex()</code> 可以确定最大的索引值 (此时为参数的数目). 但是, 如果没有参数, MaxIndex 返回一个空字符串.</p>
<p>由于需要为参数列表创建一个新对象, 最简单的可变参数函数允许使用方便的简写形式创建数组:</p>
<pre><em>; 创建数组的方法有三种:</em>
arr := Object(1, x, 2, y, 3, z)
arr := Object(), arr.Insert(1, x, y, z)
arr := Array(x, y, z)

Array(values*) {
    return values
}</pre>
<p>请注意:</p>
<ul>
  <li>"可变" 参数只可以出现在形式参数列表的末尾.</li>
  <li><a href="misc/RegExCallout.htm">RegEx callouts</a> 的函数不能是可变参数函数; 允许使用 "可变" 参数但必须留空.</li>
  <li><a href="commands/RegisterCallback.htm">Callbacks</a> <a href="commands/RegisterCallback.htm#Indirect">通过地址</a> 而不是数组传递剩余的参数.</li>
</ul>
<h3 id="VariadicCall">可变参数函数调用</h3>
<p>虽然可变参数函数可以 <i>接受</i> 可变数目的参数, 不过在函数调用中使用相同的语法可以把参数组成的数组传递给 <i>任何</i> 函数或 <a href="Objects.htm#SyntaxInvoke">对象 getter/setter</a>:</p>
<pre>substrings := Object(), substrings._Insert(1, "one", "two", "three")
MsgBox % Join("`n", <b class="blue">substrings*</b>)</pre>
<p>请注意:</p>
<ul>
  <li>在源数组中参数的编号从 1 开始.</li>
  <li>数组中可选参数可以完全省略.</li>
  <li>数组中的参数可以通过编号或名称传递.</li>
  <li>目标函数也可以是可变参数的, 此时命名项目被复制即使它们没有一致的形式参数.</li>
</ul>
<p>已知限制:</p>
<ul>
  <li>只有实际中最后一个参数可以用这种方法展开. 例如, <code>Func(x, y*)</code> 是支持的但 <code>Func(x*, y)</code> 不支持.</li>
  <li>在星号 (<code>*</code>) 和参数列表中最后的形式参数之间不能存在任何非空白字符.</li>
  <li>对象 getters/setters/methods 不支持命名参数.</li>
</ul>
<h2 id="Locals">局部变量和全局变量 </h2>
<h3>局部变量</h3>
<p>默认情况下在函数中创建或引用的所有变量都是 <em>局部</em> 的 (除了内置变量例如 <a href="misc/Clipboard.htm">Clipboard</a>, <a href="misc/ErrorLevel.htm">ErrorLevel</a>, 和 <a href="Variables.htm#TimeIdle">A_TimeIdle</a>). 每个局部变量的内容只在它所在的函数中可见. 因此, 一个局部变量可以和一个全局变量有相同的名称却有着不同的内容. 最后, 所有的局部变量在函数被调用时都以空值开始.</p>
<h3 id="Global">全局变量</h3>
<p>要在函数中引用一个已有的全局变量 (或创建一个新的), 需要在使用前声明此变量为全局的. 例如:</p>
<pre>LogToFile(TextToLog)
{
    global LogFileName  <em>; 此全局变量之前已经在函数外的某个地方赋值了.</em>
    FileAppend, %TextToLog%`n, %LogFileName%
}</pre>
<p><a name="AssumeGlobal"></a><strong>假设全局模式</strong>: 如果一个函数需要引用或创建大量的全局变量, 通过在函数的首行使用单词 "global" 或声明一个局部变量可以把函数定义为假设其所有的变量都是全局的 (除了它的参数). 例如:</p>
<pre>SetDefaults()
{
    global  <em>; 如果函数的首行是类似于 "local MyVar" 这样的, 那么这个单词可以省略.</em>
    MyGlobal := 33  <em>; 把 33 赋值给一个全局变量, 必要时首先创建变量.</em>
    local x, y:=0, z  <em>; 在这种模式中局部变量必须进行声明, 否则它们被假设为全局的.</em>
}</pre>
<p>函数还可以使用这种假设全局模式来创建全局 <a href="misc/Arrays.htm">数组</a>, 例如循环赋值给 <code>Array%A_Index%</code>.</p>
<h3 id="static">静态变量</h3>
<p>静态变量总是隐式的局部变量, 但和局部变量的区别是它们的值在多次调用期间是记住的. 例如:</p>
<pre>LogToFile(TextToLog)
{
    <strong>static</strong> LoggedLines = 0
    LoggedLines += 1  <em>; 保持局部的计数 (它的值在多次调用期间是记住的).</em>
    global LogFileName
    FileAppend, %LineCount%: %TextToLog%`n, %LogFileName%
}</pre>
<p><a name="InitStatic"></a><strong>静态初始化</strong>: 在 1.0.46 以前的版本中, 所有的静态变量都是以空值开始; 所以要检查一个静态变量首次被使用的唯一方法是检查它是否为空值. 在 1.0.46+ 版本中, 静态变量可以初始化为 <code>""</code> 外的其他值, 通过后面跟着 <code>:=</code> 或 <code>=</code> 和下列形式的其中一种: 真, 假, 原义的整数, 原义的浮点数或引号包围的/原义的字符串如 <code>"fox"</code>. 例如: <code>static X:=0, Y:="fox"</code>. 每个静态变量只初始化一次 (在脚本开始执行前).</p>
<p><span class="ver">[AHK_L 58+]:</span> <code>Static var := expression</code> 被支持. 在自动执行段前, 根据脚本中出现的顺序所有这样的表达式都被立即计算.</p>
<p><a name="AssumeStatic"></a><strong>假设静态模式</strong> <span class="ver">[v1.0.48+]:</span> 通过在函数的首行使用单词 "static" 可以把函数定义为假设其所有的变量都是静态的 (除了它的参数). 例如:</p>
<pre>GetFromStaticArray(WhichItemNumber)
{
    <strong>static</strong>
    static FirstCallToUs := true  <em>; A static declaration's initializer still runs only once (upon startup).</em>
    if FirstCallToUs  <em>; Create a static array during the first call, but not on subsequent calls.</em>
    {
        FirstCallToUs := false
        循环 10
            StaticArray%A_Index% := "Value #" . A_Index
    }
    return StaticArray%WhichItemNumber%
}</pre>
<p>在假设静态模式中, 任何非静态变量都必须声明为局部变量或全局变量.</p>
<h3>关于局部和全局的更多信息</h3>
<p>如这些例子演示的那样, 通过逗号分隔多个变量从而在同一行声明:</p>
<pre>global LogFileName, MaxRetries := 5
static TotalAttempts = 0, PrevResult</pre>
<p><a name="DeclareInit"></a>在 1.0.46+ 版本中, 一个局部或全局变量可以在同一行初始化如同声明那样, 通过后面跟着 <code>:=</code> 或 <code>=</code> 和任意 <a href="Variables.htm#Expressions">表达式</a> (在声明中 <code>=</code> 运算符作用等同于 <code>:=</code> ). 与 <a href="#InitStatic">静态初始化</a> 不同, 在每次调用函数时都执行局部变量和全局变量的初始化, 但仅当控制流实际到达它们所在语句时. 换句话说, 一行像 <code>local x = 0</code> 和写成两个单独的行有相同的效果: <code>local x</code> 后面跟着 <code>x = 0</code>.</p>
<p>因为单词 <em>local</em>, <em>global</em>, 和 <em>static</em> 是在脚本运行时立即处理的, 所以不能使用 <a href="commands/IfExpression.htm">IF 语句</a> 有条件的声明变量. 换句话说, IF 或 ELSE 的 <a href="commands/Block.htm">区块</a> 内的声明无条件对在声明和函数的闭括号之间的所有行生效. 同时注意目前还不能声明动态变量例如 <code>global Array%i%</code>.</p>
<p>对于创建 <a href="misc/Arrays.htm">数组</a> 的命令 (例如 <a href="commands/StringSplit.htm">StringSplit</a>), 如果 <a href="#AssumeGlobal">假设全局模式</a> 没有生效或数组的首个元素已经声明为局部变量时创建的数组是局部的 (如果函数的某个参数被传递时也是这样 -- 即使此参数为 <a href="#ByRef">ByRef</a> 类型 -- 因为参数与局部变量相似). 相反地, 如果首个元素已经 <a href="#Global">声明为全局的</a>, 则创建全局数组. <a href="commands/StringSplit.htm">StringSplit</a> 的首个元素为 ArrayName0. 对于其他创建数组的命令例如 <a href="commands/WinGet.htm">WinGet List</a>, 首个元素为 ArrayName (即没有数字).</p>
<p><a name="DynVar"></a><a name="Dynamic" id="Dynamic"></a>在函数中, 任何动态变量引用例如 <code>Array%i%</code> 总是解析为局部变量除非不存在这样名称的变量, 此时如果存在全局变量则使用全局变量. 如果两者都不存在那么需要先创建变量才能使用, 当 <a href="#AssumeGlobal">假设全局模式</a> 模式没有生效时它被创建为局部变量. 因此, 仅当函数被定义为 <a href="#AssumeGlobal">假设全局</a> 函数时, 函数中才可以手动创建全局 <a href="misc/Arrays.htm">数组</a> (例如使用 <code>Array%i% := A_Index</code> 的方法).</p>
<p><strong>常见疑点</strong>: 任何对变量的 <em>非</em> 动态引用都会在脚本运行时创建那个变量. 例如, 在函数外使用, <code>MsgBox %Array1%</code> 会在脚本运行的时候创建 Array1 为全局变量. 相反地, 在函数中使用 <code>MsgBox %Array1%</code> 会在脚本运行的时候创建 Array1 为函数的一个局部变量(除非 <a href="#AssumeGlobal">假设全局</a> 模式生效).</p>
<h2 id="DynCall"><a name="dynamic"></a>动态调用函数 </h2>
<p>在 1.0.47.06+ 版本中, 可以通过百分号动态调用一个函数 (即使是 <a href="#BuiltIn">内置函数</a>) . 例如, <code>%Var%(x, "fox") </code>将调用名称保存在 <em>Var</em> 中的函数. 同样地, <code>Func%A_Index%()</code> 将调用 Func1() 或 Func2() 等., 取决于 A_Index 的当前值.</p>
<p>如果函数由于后面的某个原因不能被调用, 包含调用的表达式的计算结果会过早静默地停止, 这样可能会导致不合理的结果:</p>
<ul>
  <li>通过使用 <code>If <a href="#IsFunc">IsFunc</a>(VarContainingFuncName) 可以避免调用一个不存在的函数</code>. 除了 <a href="#BuiltIn">内置函数</a>, 被调用的其他函数的 <a href="#define">定义</a> 必须明确存在于脚本中, 通过例如 <a href="commands/_Include.htm">#Include</a> 或对 <a href="#lib">库函数</a> 的非动态调用的方法.</li>
  <li>通过检查 <a href="#IsFunc">IsFunc()</a> 的返回值 (这是必须参数的数目加上一的数字) 可以避免传递太少的参数. 注意: 在 1.0.48+ 版本中, 允许传递过多的参数; 每个额外的参数都被完全计算 (包括任何函数调用) 后丢弃.</li>
  <li>传递不适当的值给 <a href="#ByRef">a ByRef</a> 参数.</li>
</ul>
<p>最后, 对函数的动态调用比正常调用稍慢因为正常的调用在脚本开始运行前解析 (查询).</p>
<h2 id="ShortCircuit">优化布尔求值</h2>
<p>当在 <a href="Variables.htm#Expressions">表达式</a> 中使用 <em>AND, OR</em> 和 <a href="Variables.htm#ternary">三元运算符</a> 时, 为了提高性能而优化它们 (不管当前是否有函数调用). 通过不计算表达式中那些不能影响它的最终结果的部分来实行优化运算. 为了说明这个观点, 请看此例:</p>
<pre>if (ColorName &lt;&gt; "" AND not FindColor(ColorName))
    MsgBox %ColorName% could not be found.</pre>
<p>在这个例子中, 如果 <em>ColorName</em> 变量为空的则永远不会调用 FindColor() 函数．　 这是由于 <em>AND</em> 的左侧结果将为 <em>false</em>, 因此其右边不可能让最终的结果为 <em>true</em>.</p>
<p>由于此特性, 所以必须明白, 如果在 <em>AND</em> 或 <em>OR</em> 的右侧调用函数, 函数可能永远不会产生副作用 (例如改变全局变量的内容).</p>
<p>同时也需要注意在嵌套的 <em>AND</em> 和 <em>OR</em> 串联表达式的求值优化. 例如, 在后面的表达式中, 每当 <em>ColorName</em> 为空时只会进行最左边的比较. 这是因为此时最左边的比较已经足够确定最终的结果:</p>
<pre>if (ColorName = "" <u>OR</u> FindColor(ColorName, Region1) <u>OR</u> FindColor(ColorName, Region2))
    break   <em>; 搜索内容为空或找到了一个匹配.</em></pre>
<p>从上面的例子可以看出, 任何耗时的函数一般应该在 <em>AND</em> 或 <em>OR</em> 的右侧调用从而提高性能. 这个方法还能避免调用接受了一个不合适的值例如空字符串的函数.</p>
<p>在 1.0.46+ 版本中, <a href="Variables.htm#ternary">三元条件运算符 (?:)</a> 也通过不计算丢弃的分支进行求值优化.</p>
<h2 id="gosub">在函数中使用子程序</h2>
<p>尽管在一个函数中不能 <a href="#define">定义</a> 其他函数, 但它可以含有子程序. 与其他子程序一样, 使用 <a href="commands/Gosub.htm">Gosub</a> 运行它们而使用 <a href="commands/Return.htm">Return</a> 返回 (这里的 Return 属于 Gosub 而不是函数).</p>
<p>已知限制: 当前每个子程序 (标签) 的名称在整个脚本中必须是唯一的. 如果存在重复的标签, 程序在运行时将通知你.</p>
<p><a name="GosubPublic"></a>如果一个函数使用 <a href="commands/Gosub.htm">Gosub</a> 跳转到一个公共子程序 (在函数外面的子程序), 所有外面的变量都是全局的而且在子程序返回前无法引用函数自身的 <a href="#Locals">局部变量</a>. 但是, 此时 A_ThisFunc 仍将包含正在执行的函数名称.</p>
<p>尽管 <a href="commands/Goto.htm">Goto</a> 到函数外的语句被忽略, 但是可以在函数中使用 <a href="commands/Gosub.htm">Gosub</a> 到外部的/公共的子程序然后在那里使用 Goto.</p>
<p>尽管一般不鼓励使用 <a href="commands/Goto.htm">Goto</a>, 但它能用来在同个函数中的一个位置跳转到其他位置. 这样有助于简化包含许多个返回点而所有这些点在返回前需要进行一些清理的复杂函数.</p>
<p>一个函数可以包含被外部调用的子程序例如 <a href="commands/SetTimer.htm">计时器</a>, <a href="commands/Gui.htm#label">GUI g 标签</a>, 和 <a href="commands/Menu.htm">菜单项</a>. 通常把它们封装到一个单独的文件中供 <a href="commands/_Include.htm">#Include</a> 使用, 这样避免了它们和脚本的 <a href="Scripts.htm#auto">自动执行段</a> 的冲突. 不过, 还有下面这些限制:</p>
<ul>
  <li>如果它们所在的函数曾经被正常调用, 这样的子程序应该只使用 <a href="#static">静态</a> 和 <a href="#Global">全局</a> 变量 (不使用 <a href="#Locals">局部</a> 变量). 这是由于中断函数调用线程的子程序 <a href="misc/Threads.htm">线程</a> (反之亦然) 可以改变被中断线程看到的局部变量的值. 此外, 在任何时候函数返回到其调用者时, 它包含的所有局部变量都被置空来释放占用的内存.</li>
  <li>这样的子程序应该只使用 <a href="#Global">全局变量</a> (不使用 <a href="#static">静态变量</a>) 作为 <a href="commands/Gui.htm#var">GUI 控件的变量</a>.</li>
  <li>当一个子程序 <a href="misc/Threads.htm">线程</a> 进入函数后, 在此线程中任何对 <a href="misc/Arrays.htm">动态变量</a> 的引用都被视为是 <a href="#Global">全局</a> 的 (包括创建数组的命令).</li>
</ul>
<h2 id="remarks">Return, Exit, 和一般说明</h2>
<p>如果函数内的执行流在遇到 <a href="commands/Return.htm">Return</a> 前到达了函数的闭括号, 那么函数结束并返回一个空值 (空字符串) 给其调用者. 每当函数明确的省略 <a href="commands/Return.htm">Return</a> 的参数时也返回一个空值.</p>
<p>当函数使用 <a href="commands/Exit.htm">Exit</a> 命令终止 <a href="misc/Threads.htm">当前线程</a> 时, 其调用者不会接收到返回值. 例如, 这个语句 <code>Var := Add(2, 3)</code> 中如果 <em>Add()</em> 退出了那么 <em>Var</em> 将保持不变. 如果函数出现了运行时错误例如 <a href="commands/Run.htm">运行</a> 一个不存在的文件 (当 <a href="commands/Run.htm#UseErrorLevel">UseErrorLevel</a> 无效时), 也将发生同样的事情.</p>
<p>为了返回一个额外的容易记住的值函数可以修改 <a href="misc/ErrorLevel.htm">ErrorLevel</a> 的值.</p>
<p>要使用一个或多个空值 (空字符串) 调用函数, 可以使用空的引号对, 例如: <code>FindColor(ColorName, "")</code></p>
<p>因为调用函数不会开启一个新 <a href="misc/Threads.htm">线程</a>, 函数对设置例如 <a href="commands/SendMode.htm">SendMode</a> 和 <a href="commands/SetTitleMatchMode.htm">SetTitleMatchMode</a> 做出的任何改变对其调用者同样有效.</p>
<p>函数的调用者可以传递一个不存在的变量或 <a href="misc/Arrays.htm">数组</a> 元素给它, 当函数期望和 <a href="#ByRef">ByRef</a> 一致的参数时这很有用. 例如, 调用 <code>GetNextLine(BlankArray%i%)</code> 将创建变量 <code>BlankArray%i%</code> 自动地作为 <a href="#Locals">局部</a> 或全局的 (取决于调用者是否在函数内并且它的 <a href="#AssumeGlobal">假设全局模式</a> 是否生效).</p>
<p>在函数中使用 <a href="commands/ListVars.htm">ListVars</a> 时, 它会显示函数的 <a href="#Locals">局部变量</a> 及其内容. 这样有助于调试脚本.</p>
<h2>风格和命名规则</h2>
<p>你会发现如果给复杂函数中的特殊变量加上独特的前缀, 会让函数更容易阅读和维护. 例如, 使用 "p" 或 "p_" 开头来命名函数中的每个参数可以让它们的性质一目了然, 尤其是当函数有许多 <a href="#Locals">局部变量</a> 吸引你注意力的时候. 同样地, 前缀 "r" 或 "r_" 可以用于 <a href="#ByRef">ByRef 参数</a>, 而 "s" 或 "s_" 可以用于 <a href="#static">静态变量</a>.</p>
<p>定义函数时可以使用 <a href="commands/Block.htm#otb">One True Brace (OTB) 风格</a>. 例如:</p>
<pre>Add(x, y) <strong>{</strong>
    return x + y
<strong>}</strong></pre>
<h2 id="include">使用 #Include 在多个脚本间共享函数</h2>
<p>可以使用 <a href="commands/_Include.htm">#Include</a> 指令 (<em>即使在脚本的顶部</em>) 从外部文件中加载函数.</p>
<p>说明: 当脚本的执行流遇到函数定义时, 它会跳过函数 (使用一种瞬时的方法) 并在函数闭括号后面的行恢复执行. 因此, 开始执行时执行流不会陷入函数中, 也不会因为在脚本的最顶部存在一个或多个函数而影响到 <a href="Scripts.htm#auto">自动执行段</a>.</p>
<h2><a name="lib" id="lib"></a>函数库: 标准库和用户库 <span class="ver">[v1.0.47+]</span> </h2>
<p>脚本可以不需要使用 <a href="commands/_Include.htm">#Include</a> 调用外部文件中的函数. 要达到此目的, 一个和函数相同名称的文件必须存在于后面库目录的其中一个里:</p>
<pre><a href="Variables.htm#ScriptDir">%A_ScriptDir%</a>\Lib\  <em>; 局部库 - 要求 AHK_L 42+.</em>
<a href="Variables.htm#MyDocuments">%A_MyDocuments%</a>\AutoHotkey\Lib\  <em>; 用户库.</em>
path-to-the-currently-running-AutoHotkey.exe\Lib\  <em>; 标准库.</em></pre>
<p>例如, 如果脚本调用一个不存在的函数 <em>MyFunc()</em>, 程序会在用户库中搜索名为 <em>MyFunc.ahk</em> 的文件. 如果这里没找到, 继续在标准库中搜索此文件. 如果仍没找到匹配的文件并且函数的名称包含一个下划线 (例如 <em>MyPrefix_MyFunc</em>), 程序会在两个库中搜索名为 <em>MyPrefix.ahk</em> 的文件如果找到则装载它. 这样使得 <em>MyPrefix.ahk</em> 可以同时包含 <em>MyPrefix_MyFunc</em> 函数和其他名称以 <em>MyPrefix_</em> 开始的相关函数.</p>
<p><span class="ver">[AHK_L 42+]:</span> 支持局部库并且局部库优先于用户库和标准库.</p>
<p>虽然一个库文件通常只包含和它的文件名称相同的单个函数, 但它还可以包含仅被此函数调用的私有函数和子程序. 然而, 这样的函数应该使用相当特殊的名称因为它们仍属于全局命名空间; 也就是说, 可以在脚本的任意位置调用它们.</p>
<p>如果在库文件中使用 <a href="commands/_Include.htm">#Include</a>, #Include 的工作目录为库文件自身所在的目录. 这可以用来创建一个重定向到一个较大的库文件, 其中包含此函数和其他相关内容.</p>
<p><a href="Scripts.htm#ahk2exe">脚本编译器 (ahk2exe)</a> 同样支持库函数. 不过, 它要求在编译器目录的上一级目录中存在一个 AutoHotkey.exe 的副本 (正常情况下是这样). 如果不存在 AutoHotkey.exe, 编译器仍可以运行但无法自动包含库函数.</p>
<p>包含在库中的函数和其他函数执行的一样好因为它们在脚本开始执行前已经被预加载了.</p>
<h2 id="BuiltIn">内置函数</h2>
<p>在内置函数参数列表末尾的任何可选参数可以完全省略. 例如, <code>WinExist("Untitled - Notepad")</code> 是有效的, 它的其他三个参数被看成是空的.</p>
<p>如果脚本定义了与内置函数同名的函数, 那么内置函数会被覆盖. 例如, 脚本会调用它自己定义的 WinExist() 函数来代替标准的那个. 然而, 这样脚本将无法调用原始的函数.</p>
<p>在 DLL 文件中的外部函数可以使用 <a href="commands/DllCall.htm">DllCall()</a> 调用.</p>
<h3>常用函数</h3>
<p><strong><a name="FileExist"></a>FileExist(FilePattern)</strong>: 如果 <em>FilePattern</em> 不存在 (如果未指定绝对路径则假定 <em>FilePattern</em> 在 <a href="Variables.htm#WorkingDir">A_WorkingDir</a> 中) 则返回一个空值 (空字符串). 否则, 它返回首个匹配的文件或文件夹的 <a href="commands/FileGetAttrib.htm#attrib">属性字符串</a> ("RASHNDOCT" 的子集). 如果文件没有属性 (很少见), 则返回 "X". <em>FilePattern</em> 可以是一个文件或文件夹的准确名称, 或者包含通配符 (* or ?). 由于空字符串被视为 "false", 所以函数的返回值总是可以作为一个准布尔值来使用. 例如, 语句 <code>if FileExist("C:\My File.txt")</code> 文件存在时将为真否则为假. 同样地, 语句 <code>if InStr(FileExist("C:\My Folder"), "D")</code> 仅当文件存在 <em>并且</em> 是个目录时才为真. 相关命令: <a href="commands/IfExist.htm">IfExist</a> 和 <a href="commands/FileGetAttrib.htm">FileGetAttrib</a>.</p>
<p><strong><a name="GetKeyState"></a>GetKeyState(<a href="KeyList.htm">KeyName</a> [, "P"</strong> or <strong>"T"])</strong>: 与 <a href="commands/GetKeyState.htm">GetKeyState 命令</a> 不同 -- 它在按下时返回 D 而在弹起时返回 U -- 此函数当按下时返回真 (1) 而弹起时返回假 (0). 如果 <em><a href="KeyList.htm">KeyName</a></em> 无效, 则返回一个空字符串. 参见 <a href="commands/GetKeyState.htm">GetKeyState</a> 了解其他返回值和用法.</p>
<p><strong><a name="InStr"></a>InStr(Haystack, Needle [, CaseSensitive = false, StartingPos = 1, Occurrence = 1])</strong>: 返回字符串 <em>Needle</em> 在字符串 <em>Haystack</em> 中出现的位置. 与 <a href="commands/StringGetPos.htm">StringGetPos</a> 不同, 首个字符位置为 1; 这是由于 0 相当于 "假", 使其成为一个直观的 "未找到" 的提示. 如果参数 <em>CaseSensitive</em> 省略或为 false, 搜索不区分大小写 (不区分的模式取决于 <a href="commands/StringCaseSense.htm">StringCaseSense</a>); 否则, 大小写必须准确匹配. 如果 <em>StartingPos</em> 省略, 默认为 1 (<em>Haystack</em> 的起点). 否则, 指定 2 从 <em>Haystack</em> 的第二个字符开始, 指定 3 从第三个开始等. 如果 <em>StartingPos</em> 超过了 <em>Haystack</em> 的长度, 则返回 0. 如果 <em>StartingPos</em> 为 0 或负数, 搜索将从末尾的偏移开始反向进行 (从右到左). 不管 <em>StartingPos</em> 的值是多少, 返回的位置总是相对于 <em>Haystack</em> 的首个字符. 例如, "abc" 在 "123abc789" 中的位置总为 4. 在 <i>Occurrence</i> 参数中指定 2 来返回第二个匹配的位置, 3 为第三个等. 相关项目: <a href="commands/RegExMatch.htm">RegExMatch()</a>, <a href="commands/IfInString.htm">IfInString</a>, 和 <a href="commands/StringGetPos.htm">StringGetPos</a>.</p>
<p><span class="CommandSyntax"><strong>RegExMatch(Haystack, NeedleRegEx [, UnquotedOutputVar = "", StartingPos = 1])</strong>: 参见 <a href="commands/RegExMatch.htm">RegExMatch</a></span><a href="commands/RegExMatch.htm">()</a>.</p>
<p><span class="CommandSyntax"><strong>RegExReplace(Haystack, NeedleRegEx [, Replacement = "", OutputVarCount = "", Limit = -1, StartingPos = 1])</strong></span>: 参见 <span class="CommandSyntax"><a href="commands/RegExReplace.htm">RegExReplace</a></span><a href="commands/RegExReplace.htm">()</a>.</p>
<p><strong><a name="SubStr"></a>SubStr(String, StartingPos [, Length])</strong> <span class="ver">[v1.0.46+]:</span> 在 <em>String</em> 中从 <em>StartingPos</em> 开始向右复制不超过 <em>Length</em> 长度的子字符串 (如果 <em>Length</em> 省略, 默认为 "所有字符"). 对于 <em>StartingPos</em>, 指定 1 从首个字符开始, 2 从第二个开始等 (如果 <em>StartingPos</em> 超过了 <em>String</em> 的长度, 则返回一个空字符串). 如果 <em>StartingPos</em> 小于 1, 它被看成是从字符串末尾开始的偏移. 例如, 0 提取最后一个字符而 -1 提取最后两个字符 (但如果 <em>StartingPos</em> 超过了字符串的左端, 提取又从首个字符开始). <em>Length</em> 是需获取的字符的最大数目 (每当字符串剩余部分太短时获取的数目会比最大值少). 指定一个负的 <em>Length </em> 从而在返回字符串的末尾省略这个数目的字符 (如果省略了全部或更多字符则返回一个空字符串). 相关项目: <a href="commands/RegExMatch.htm">RegExMatch()</a>, <a href="commands/StringMid.htm">StringMid</a>, <a href="commands/StringLeft.htm">StringLeft/Right</a>, <a href="commands/StringTrimLeft.htm">StringTrimLeft/Right</a>.</p>
<p><strong><a name="StrLen"></a>StrLen(String)</strong>: 返回 <em>String</em> 的长度. 如果 <em>String</em> 是之前由 <a href="misc/Clipboard.htm#ClipboardAll">ClipboardAll</a> 所赋值的变量, 则返回其总大小. 相关命令: <a href="commands/StringLen.htm">StringLen</a>.</p>
<p><strong><a name="WinActive"></a>WinActive([WinTitle, WinText, ExcludeTitle, ExcludeText])</strong>: 如果活动窗口匹配指定的条件则返回其 <a href="commands/WinGet.htm">唯一 ID (HWND)</a>. 如果不匹配, 函数返回 0. 因为所有非零值都被视为 "真", 语句 <code>if WinActive("WinTitle")</code> 每当 <em>WinTitle</em> 是活动时为真. 参数 <em>WinTitle</em> 支持 ahk_id, ahk_class, 和其他特殊字符串. 关于窗口激活的这些和其他相关信息请参见 <a href="commands/IfWinActive.htm">IfWinActive</a> 了解详情. 注意: 获取活动窗口的唯一 ID 的简便方法是使用 <code>ActiveHwnd := WinExist("A")</code></p>
<p><strong><a name="WinExist"></a>WinExist([WinTitle, WinText, ExcludeTitle, ExcludeText])</strong>: 返回以十六进制整数表示的首个匹配窗口的 <a href="commands/WinGet.htm">唯一 ID (HWND)</a> (没有则为 0). 因为所有非零值都被视为 "真", 语句 <code>if WinExist("WinTitle")</code> 每当 <em>WinTitle</em> 存在时为真. 参数 <em>WinTitle</em> 支持 ahk_id, ahk_class, 和其他特殊字符串. 关于窗口搜索的这些和其他相关信息请参见 <a href="commands/IfWinExist.htm">IfWinExist</a> 了解详情.</p>
<h3><a></a>杂项函数</h3>
<p><strong><a name="Asc"></a>Asc(String)</strong>: 返回 <em>String</em> 中首个字符的 ASCII 码 (介于 1 到 255 之间的数字). 如果 <em>String</em> 为空, 则返回 0.</p>
<p><strong><a name="Chr"></a>Chr(Number)</strong>: 返回与 <em>Number</em> 表示的 ASCII 码对应的单个字符. 如果 <em>Number</em> 不是介于 1 和 255 及其之间, 则返回一个空字符串. 常用的 ASCII 码包括 9 (Tab), 10 (换行), 13 (回车), 32 (空格), 48-57 (数字 0-9), 65-90 (大写字母 A-Z), 和 97-122 (小写字母 a-z).</p>
<p><strong>DllCall()</strong>: 参见 <a href="commands/DllCall.htm">DllCall()</a>. </p>
<p><strong>FileOpen()</strong>: 提供面向对象文件 I/O. 参见 <a href="commands/FileOpen.htm">FileOpen()</a> 了解详情.
<p><strong><a name="IsFunc"></a>IsFunc(FunctionName)</strong> <span class="ver">[v1.0.48+]:</span> 如果 <em>FunctionName</em> 不是显式出现在脚本中 (通过这样的方法, 例如 <a href="commands/_Include.htm">#Include</a> 或对 <a href="#lib">库函数</a> 的非动态调用), IsFunc() 返回 0. 否则, 它返回函数最少的参数个数加一 (例如 1 为函数可以不需要参数, 2 为函数至少需要一个参数等). 例如, 语句 <code>if IsFunc("MyFunc")</code> 和 <code>if IsFunc(VarContainingFunctionName)</code> 函数存在时将为真, 否则为假. 也请参见: <a href="#DynCall">动态函数调用</a>, <a href="Variables.htm#ThisFunc">A_ThisFunc</a></p>
<p><strong><a name="IsLabel"></a>IsLabel(LabelName)</strong>: 如果 <em>LabelName </em> 作为 <a href="commands/Gosub.htm">子程序</a>, <a href="Hotkeys.htm">热键</a> 或 <a href="Hotstrings.htm">热字串</a> (不包括 <em>LabelName</em> 中末尾的冒号) 存在于脚本中则返回一个非零数字. 例如, 语句 <code>if IsLabel(VarContainingLabelName)</code> 标签存在时将为真, 否则为假. 在类似 <a href="commands/Gosub.htm">Gosub</a>, <a href="commands/Hotkey.htm">Hotkey</a>, <a href="commands/Menu.htm">Menu</a> 和 <a href="commands/Gui.htm">Gui</a> 的命令中指定一个动态标签时, 使用此函数对避免运行时错误很有用. 也请参见: <a href="Variables.htm#ThisLabel">A_ThisLabel</a> </p>
<p><strong><a name="IsObject"></a>IsObject()</strong> <span class="ver">[AHK_L 31+]:</span> 判断某个值是否为对象. 也请参见: <a href="Objects.htm">Objects</a>.</p>
<p><strong>ListView 和 </strong><strong>TreeView 函数</strong>: 参见 <a href="commands/ListView.htm">ListView</a> 和 <a href="commands/TreeView.htm">TreeView</a> 页面了解详情.</p>
<p><strong><a name="NumGet"></a>NumGet(VarOrAddress [, Offset = 0][, Type = "UPtr"])</strong> <span class="ver">[v1.0.47+]:</span> 返回在指定地址+偏移量存储的二进制数. 对于 <em>VarOrAddress</em>, 传递 <code>MyVar</code> 相当于传递 <code>&amp;MyVar</code>. 然而, 省略 "&amp;" 可以执行地更好并确保目标地址是 <a href="commands/VarSetCapacity.htm">有效的</a> (无效的地址返回 ""). 与之相比, 传递给 <em>VarOrAddress</em> 除裸变量之外的任何东西都被视为原始地址; 因此, 指定 <code>MyVar+0</code> 强制使用 MyVar 中的数字代替 MyVar 自身的地址. 对于 <em>Type</em>, 可以指定为 UInt, Int, Int64, Short, UShort, Char, UChar, Double, Float 或 Ptr (不过与 DllCall 有些不同, 作为原义字符串使用时它们必须包围在引号中); 更多详情参见 <a href="commands/DllCall.htm#types">DllCall 类型</a>. <span class="ver">[AHK_L 57+]:</span> <i>Offset</i> 参数可以完全省略; 例如, <code>NumGet(var, "int")</code> 是有效的.</p>
<p><strong><a name="NumPut"></a>NumPut(Number, VarOrAddress [, Offset = 0][, Type = "UPtr"])</strong> <span class="ver">[v1.0.47+]:</span> 以二进制格式把 <em>Number</em> 存储到指定地址+偏移量并且返回刚写入项目右边的地址. 对于 <em>VarOrAddress</em>, 传递 <code>MyVar</code> 相当于传递 <code>&amp;MyVar</code>. 然而, 省略 "&amp;" 可以执行地更好并确保目标地址是 <a href="commands/VarSetCapacity.htm">有效的</a> (无效的地址返回 ""). 与之相比, 传递给 <em>VarOrAddress</em> 除裸变量之外的任何东西都被视为原始地址; 因此, 指定 <code>MyVar+0</code> 强制使用 MyVar 中的数字代替 MyVar 自身的地址. 对于 <em>Type</em>, 可以指定为 UInt, Int, Int64, Short, UShort, Char, UChar, Double, Float 或 Ptr (不过与 DllCall 有些不同, 作为原义字符串使用时它们必须包围在引号中+) (在 1.0.48+ 版本中支持 UInt64); 更多详情参见 <a href="commands/DllCall.htm#types">DllCall 类型</a>. 如果一个整数太大而不适合指定的 <em>类型</em>, 它最重要的字节被忽略了; 例如 <code>NumPut(257, var, 0, "Char")</code> 将存储数字 1. <span class="ver">[AHK_L 57+]:</span> <i>Offset</i> 参数可以完全省略; 例如, <code>NumPut(x, var, "int")</code> 是有效的.</p>
<p><strong>OnMessage(MsgNumber [, "FunctionName"])</strong>: 监视消息/事件. 请参见 <a href="commands/OnMessage.htm">OnMessage()</a> 了解详情.</p>
<p><strong>StrGet(Address [, Length] [, Encoding = None ] )</strong> <span class="ver">[AHK_L 46+]:</span> 从内存地址复制字符串, 并可以对其在不同代码页间进行转换. 请参见 <a href="commands/StrPutGet.htm">StrGet()</a> 了解详情.</p>
<p><strong>StrPut(String, Address [, Length] [, Encoding = None ] )</strong> <span class="ver">[AHK_L 46+]:</span> 复制字符串到内存地址, 并可以对其在不同代码页间进行转换. 请参见 <a href="commands/StrPutGet.htm">StrPut()</a> 了解详情.</p>
<p><strong>RegisterCallback()</strong>: 参见 <a href="commands/RegisterCallback.htm">RegisterCallback()</a>.</p>
<p><strong>Trim()</strong> <span class="ver">[AHK_L 31+]:</span> 参见 <a href="commands/Trim.htm">Trim()</a>.</p>
<p><strong>VarSetCapacity(UnquotedVarName [, RequestedCapacity, FillByte])</strong>: 增加或清空变量占用的内存. 请参见 <a href="commands/VarSetCapacity.htm">VarSetCapacity()</a> 了解详情.</p>
<h3 id="Math">通用数学函数 </h3>
<p>注意: 如果任一传入参数是非数值的时数学函数通常返回一个空值 (空字符串).</p>
<p><strong><a name="Abs"></a>Abs(Number)</strong>: 返回 <em>Number</em> 的绝对值. 返回值的类型和 <em>Number</em> 相同 (整数或浮点数).</p>
<p><strong><a name="Ceil"></a>Ceil</strong><strong>(Number)</strong>: 返回由 <em>Number</em> 向上取整到最近的整数 (不带任何 .00 后缀). 例如, <code>Ceil(1.2)</code> 是 2 而 <code>Ceil(-1.2)</code> 是 -1.</p>
<p><strong><a name="Exp"></a>Exp(N)</strong>: 返回 <em>e</em> (其近似值为 2.71828182845905) 的 <em>N</em> 次幂. <em>N</em> 可以为负数也可以为小数. 要计算 <em>e</em> 以外的其他数的次幂, 使用 <a href="Variables.htm#pow">** 运算符</a>.</p>
<p><strong><a name="Floor"></a>Floor(Number)</strong>: 返回由 <em>Number</em> 向下取整到最近的整数 (不带任何 .00 后缀). 例如, <code>Floor(1.2)</code> 是 1 而 <code>Floor(-1.2)</code> 是 -2.</p>
<p><strong><a name="Log"></a>Log(Number)</strong>: 返回 <em>Number</em> 的对数 (底数为 10). 结果格式化为 <a href="commands/SetFormat.htm">浮点数</a>. 如果 <em>Number</em> 为负数, 则返回一个空字符串.</p>
<p><strong><a name="Ln"></a>Ln(Number)</strong>: 返回 <em>Number</em> 的自然对数 (底数为 e). 结果格式化为 <a href="commands/SetFormat.htm">浮点数</a>. 如果 <em>Number</em> 为负数, 则返回一个空字符串.</p>
<p><strong><a name="Mod"></a>Mod(Dividend, Divisor)</strong>: 求模. 返回被除数 <em>Dividend</em> 除以除数 <em>Divisor</em> 后得到的余数. 结果的正负总是与被除数一致. 例如, <code>mod(5, 3)</code> 和 <code>mod(5, -3)</code> 都得到结果 2, 但 <code>mod(-5, 3)</code> 和<code>mod(-5, -3)</code> 得到结果 -2. 如果任何一个参数为浮点数, 那么结果也是浮点数. 例如, <code>mod(5.0, 3)</code> 是 2.0 而 <code>mod(5, 3.5)</code> 是 -1.5. 如果除数为零, 函数返回空值 (空字符串).</p>
<p><strong><a name="Round"></a>Round(Number [, N])</strong>: 如果 <em>N</em> 省略或为 0, 则 <em>Number</em> 被取整到最近的整数. 如果 <em>N</em> 为正数, 则 <em>Number</em> 被取整到 <em>N</em> 个小数位. 如果 <em>N</em> 为负数, 则 <em>Number</em><em> </em>被取整到十进制小数点左边 <em>N</em> 位. 例如, <code>Round(345, -1)</code> 结果为 350 而 Round (345, -2) 结果为 300. 与 <a href="commands/Transform.htm">Transform Round</a> 不同, 每当 <em>N</em> 省略或小于 1 时结果不含 .000后缀. 在 1.0.44.01+ 版本中, 大于零的 <em>N</em> 值会准确显示 <em>N </em>个小数位而不服从 <a href="commands/SetFormat.htm">SetFormat</a> 的设置. 要避免这种情况, 对 Round() 的返回值再进行一次数学运算; 例如: <code>Round(3.333, 1)<strong>+0</strong></code>.</p>
<p><strong><a name="Sqrt"></a>Sqrt(Number)</strong>: 返回 <em>Number</em> 的平方根. 结果格式化为 <a href="commands/SetFormat.htm">浮点数</a>. 如果 <em>Number</em> 为负数, 则函数返回空值 (空字符串).</p>
<h3>三角函数</h3>
<p><strong><a name="Sin"></a><a name="Cos"></a><a name="Tan"></a>Sin(Number)</strong> | <strong>Cos(Number)</strong> | <strong>Tan(Number) </strong>: 返回 <em>Number</em> 的正弦|余弦|正切三角函数值. <em>Number</em> 必须用弧度表示.</p>
<p><strong><a name="ASin"></a>ASin(Number)</strong>: 返回弧度表示的反正弦值 (其正弦值为 <em>Number</em>). 如果 <em>Number</em> 小于 -1 或大于 1, 则函数返回空值 (空字符串).</p>
<p><strong><a name="ACos"></a>ACos(Number)</strong>: 返回弧度表示的反余弦值 (其余弦值为 <em>Number</em>). 如果 <em>Number</em> 小于 -1 或大于 1, 则函数返回空值 (空字符串).</p>
<p><strong><a name="ATan"></a>ATan</strong><strong>(Number)</strong>: 返回弧度表示的反正切值 (其正切值为 <em>Number</em>).</p>
<p><strong>注意:</strong> 要将弧度转换成角度, 将其乘以 180/pi (约为 57.29578). 要将角度转换成弧度, 将其乘以 pi/180 (约为 0.01745329252). pi 的值 (约为 3.141592653589793) 为 1 的反正切值乘以 4.</p>
<h3>其他函数</h3>
<p><a href="http://file.autohotkey.net/Titan/functions.html">Titan 的命令函数</a>: 为每个有 OutputVar 的 AutoHotkey 命令提供一个可调用的函数. 可以通过 <a href="commands/_Include.htm">#Include</a> 把这个库包含在任何一个脚本中.</p>
</body>
</html>
